package util

import (
	"bytes"
	"litter-api/app/util/pool"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"github.com/pkg/errors"
	"io/ioutil"
	"net/url"
	"reflect"
	"strconv"
	"strings"
	"time"
)

func GetValidMsg(err error, obj interface{}) string {
	fmt.Println("error_msg", err)
	getObj := reflect.TypeOf(obj)
	if errs, ok := err.(validator.ValidationErrors); ok {
		for _, e := range errs {
			if f, exist := getObj.Elem().FieldByName(e.Field()); exist {
				return f.Tag.Get("errorMsg")
			}
		}
	}
	return err.Error()
}

func GetReqData(data interface{}) []string {
	var str_data string
	if rec, ok := data.([]interface{}); ok {
		for _, val := range rec {
			str_data = str_data + "," + fmt.Sprintf("%v", val)
		}
	} else {
		str_data = data.(string)
	}
	split_data := strings.Split(strings.TrimLeft(str_data, ","), ",")
	return split_data
}

func ToSlice(arr interface{}) []interface{} {
	v := reflect.ValueOf(arr)
	if v.Kind() != reflect.Slice {
		return make([]interface{}, 0)
	}
	l := v.Len()
	ret := make([]interface{}, l)
	for i := 0; i < l; i++ {
		ret[i] = v.Index(i).Interface()
	}
	return ret
}

//查找字符是否在数组中
func InArray(target interface{}, search interface{}) bool {
	targetValue := reflect.ValueOf(target)
	if reflect.TypeOf(search).Kind() == reflect.Int ||
		reflect.TypeOf(search).Kind() == reflect.Int8 ||
		reflect.TypeOf(search).Kind() == reflect.Int16 ||
		reflect.TypeOf(search).Kind() == reflect.Int32 ||
		reflect.TypeOf(search).Kind() == reflect.Int64 {

		search = strconv.Itoa(ParseIntParam(search))
	} else if reflect.TypeOf(search).Kind() == reflect.Float64 ||
		reflect.TypeOf(search).Kind() == reflect.Float32 {
		search = ToString(search)
	} else if reflect.TypeOf(search).Kind() == reflect.String {
		search = ToString(search)
	} else {
		search = ToString(search)
	}
	switch reflect.TypeOf(target).Kind() {
	case reflect.Slice, reflect.Array:
		for i := 0; i < targetValue.Len(); i++ {
			targetOne := ""
			//  转换数据类型
			if targetValue.Index(i).Kind() == reflect.Int {
				targetOne = strconv.Itoa(ParseIntParam(targetValue.Index(i).Interface()))
			} else {
				// 非Int类型需要转换为interface之后转换为 string
				targetOne = strconv.Itoa(ParseIntParam(targetValue.Index(i).Interface()))
			}

			//fmt.Println("####")
			//fmt.Println(targetOne)
			//fmt.Println(search)
			//fmt.Println(reflect.TypeOf(targetOne))
			//fmt.Println(reflect.TypeOf(search))
			//fmt.Println(targetOne == search)
			//fmt.Println("####")
			if targetOne == search {
				return true
			}
		}
	case reflect.Map:
		if targetValue.MapIndex(reflect.ValueOf(search)).IsValid() {
			return true
		}
	}

	return false
}

func ToJsonMap(data string) map[string]interface{} {
	var extJson []byte
	extJson = []byte(data)
	var ext interface{}
	json.Unmarshal(extJson, &ext)

	jsonMap := make(map[string]interface{})
	if ext != nil {
		jsonMap = ext.(map[string]interface{})
	}
	return jsonMap
}

func IToIntString(val interface{}) string {

	if reflect.TypeOf(val).Kind() == reflect.String {
		return val.(string)
	} else if reflect.TypeOf(val).Kind() == reflect.Float64 || reflect.TypeOf(val).Kind() == reflect.Float32 {
		val = val.(interface{})
		valInt := int(val.(float64))
		return strconv.Itoa(valInt)
	} else {
		return ""
	}
}

func IToString(val interface{}) string {

	if reflect.TypeOf(val).Kind() == reflect.String {
		return val.(string)
	} else if reflect.TypeOf(val).Kind() == reflect.Float64 || reflect.TypeOf(val).Kind() == reflect.Float32 {
		val = val.(interface{})
		valInt := int(val.(float64))
		return strconv.Itoa(valInt)
	} else {
		return ""
	}
}

func IToInt(val interface{}) int {
	return int(val.(float64))
}

func ParseIntParam(val interface{}) int {
	//fmt.Println(reflect.TypeOf(val).Kind())
	if val == nil {
		return 0
	}
	if reflect.TypeOf(val).Kind() == reflect.String {
		num, _ := strconv.Atoi(val.(string))
		return num
	} else if reflect.TypeOf(val).Kind() == reflect.Float64 || reflect.TypeOf(val).Kind() == reflect.Float32 {
		val = val.(interface{})
		return int(val.(float64))
	} else if reflect.TypeOf(val).Kind() == reflect.Int ||
		reflect.TypeOf(val).Kind() == reflect.Uint ||
		reflect.TypeOf(val).Kind() == reflect.Int8 ||
		reflect.TypeOf(val).Kind() == reflect.Int16 ||
		reflect.TypeOf(val).Kind() == reflect.Int32 ||
		reflect.TypeOf(val).Kind() == reflect.Int64 {
		return val.(int)
	} else {
		return -1
	}
}

// 检查参数是否为空
func CheckParam(reqData map[string]interface{}, keyArr []string) error {

	for _, v := range keyArr {
		val, exists := reqData[v]
		if exists == false {
			return errors.New(v + "参数不存在2")
		}
		if val == nil || val == "" {
			return errors.New(v + "不能为空1")
		}
	}
	return nil
}

// MapSearchKey 搜索key是否再Map中
func MapSearchKey(Maps map[string]interface{}, searchKey string, defaultValue interface{}) interface{} {
	val, isExists := Maps[searchKey]
	if isExists == true {
		return val
	} else {
		return defaultValue
	}
}

// 记录日志
func Log(logParam ...interface{}) bool {

	// 没有任何参数直接返回
	paramLen := len(logParam)
	if paramLen <= 0 {
		return true
	}
	// 任意参数
	for _, logItem := range logParam {
		pool.Logger.Info(ToString(logItem))
	}
	return true
}

// 将格式化时间转换为时间戳
func ToTimeStamp(Param interface{}) int64 {
	ParamStr := ToString(Param)
	layout := "2006-01-02 15:04:05"
	if strings.LastIndex(ParamStr, "+08:00") != -1 {
		layout = time.RFC3339
	}
	timeObj, _ := time.ParseInLocation(layout, ToString(ParamStr), time.Local)
	return timeObj.Unix()
}

func DateRFCChange(format, dateFormat, inDate string) string {
	t1, e := time.Parse(
		format,
		inDate)
	if e != nil {
		fmt.Println(e)
	}
	return t1.Format(dateFormat)
}

// 格式化MYSQL取出的时间
func FormatMysqlDate(inDate string) string {
	//fmt.Println("inDate")
	//fmt.Println("inDate")
	//fmt.Println(inDate)
	//fmt.Println("inDate")
	if strings.LastIndex(inDate, "+08:00") != -1 {
		dateFormat := "2006-01-02 15:04:05"
		layout := time.RFC3339
		t1, e := time.Parse(
			layout,
			inDate)
		if e != nil {
			fmt.Println(e)
		}
		return t1.Format(dateFormat)
	} else {
		return inDate
	}

}

// 获取当前时间戳
func GetNowTimeStamp() int64 {
	return time.Now().Unix()
}

// 获取当前时间戳
func GetNowDate() string {
	layout := "2006-01-02 15:04:05"
	t := time.Now()
	return t.Format(layout)
}

// 获取header
func GetRequestHeader(c *gin.Context) map[string]interface{} {
	header := c.Request.Header
	headerMap := make(map[string]interface{})
	for k, v := range header {
		key := strings.ToLower(k)
		if reflect.TypeOf(v).Kind() == reflect.Slice {
			headerMap[key] = v[0]
		} else {
			headerMap[key] = v
		}
	}
	return headerMap
}

//  反转Slice
func RevSlice(originSli []string) []string {
	sliLen := len(originSli)
	var RevSli = make([]string, sliLen)
	for i := sliLen - 1; i >= 0; i++ {
		RevSli = append(RevSli, originSli[i])
	}
	return RevSli
}

func BuildPageData(count int, list interface{}) map[string]interface{} {
	var result = make(map[string]interface{})
	result["total"] = count
	result["list"] = list
	return result
}

// 解析参数为map
func ParseRequestParam(c *gin.Context) map[string]interface{} {

	urlMap := getUrlParam(c)
	Log("URL DATA :", urlMap)

	// 获取请求体中的JSON数据
	var jsonMap map[string]interface{}
	c.ShouldBind(&jsonMap)

	if c.Request.Method == "GET" && c.Request.Header.Get("Content-Type") == "application/json" {
		getRawData, _ := c.GetRawData()
		c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(getRawData))
		extJson := []byte(getRawData)
		var ext interface{}
		json.Unmarshal(extJson, &ext)
		jsonMap = ext.(map[string]interface{})
		Log("GET JSON DATA :", jsonMap)
	}
	Log("JSON DATA :", jsonMap)
	// 获取PostForm参数
	formData := getPostFormParam(c)
	Log("POST DATA :", formData)

	// 合并数据并返回
	alLReqData := MapMerge(formData, urlMap, jsonMap)

	return alLReqData
}

// 获取请求字符串
func MapMerge(maps ...map[string]interface{}) map[string]interface{} {
	if len(maps) == 0 {
		return nil
	}
	allMap := make(map[string]interface{}, 0)
	for _, v := range maps {
		if len(allMap) == 0 {
			allMap = v
		} else {
			if len(v) > 0 {
				for mk, mv := range v {
					allMap[mk] = mv
				}
			}
		}
	}
	return allMap
}

// 获取请求字符串
func getPostFormParam(c *gin.Context) map[string]interface{} {
	var formMap = make(map[string]interface{}, 0)
	for k, v := range c.Request.PostForm {
		formMap[k] = arrayToString(v)
	}
	return formMap
}

// 获取请求字符串
func getUrlParam(c *gin.Context) map[string]interface{} {
	route := c.FullPath()
	fullPath := fmt.Sprintf("%v", c.Request.URL)
	// 路由和路径相同返回空
	if route == fullPath {
		return nil
	}
	// 拼接一个? 解析出URL参数
	if strings.LastIndex(route, "?") < 0 {
		route += "?"
	}
	replace := strings.Replace(fullPath, route, "", 1)
	urlParam, _ := url.ParseQuery(replace)
	// 解析参数为map格式
	var urlMap = make(map[string]interface{}, 0)
	for k, v := range urlParam {
		urlMap[k] = arrayToString(v)
	}
	return urlMap
}

// 数组类型slice转换为 string
func arrayToString(arr []string) string {
	var result string
	for _, i := range arr { //遍历数组中所有元素追加成string
		result += i
	}
	return result
}

func IsNil(val interface{}, errorMsg string) bool {
	if val == nil {
		return true
	}
	return false
}

// 输出字符串格式
func ToString(Param interface{}) string {
	return fmt.Sprintf("%v", Param)
}

func ToFloat(Map map[string]interface{}, MapKey string) float64 {
	jsonStr, _ := json.Marshal(Map)
	var back_data map[string]interface{}
	json.Unmarshal([]byte(jsonStr), &back_data)
	stringFloat := ToString(back_data[MapKey])
	value, _ := strconv.ParseFloat(stringFloat, 64)

	return value
}

//支持中文截取, 支持end 负数截取
func SubStr(source interface{}, start int, end int) string {
	str := source.(string)
	var r = []rune(str)
	length := len(r)
	subLen := end - start

	for {
		if start < 0 {
			break
		}
		if start == 0 && subLen == length {
			break
		}
		if end > length {
			subLen = length - start
		}
		if end < 0 {
			subLen = length - start + end
		}
		var substring bytes.Buffer
		if end > 0 {
			subLen = subLen + 1
		}
		if subLen > length {
			subLen = length
		}
		for i := start; i < subLen; i++ {
			substring.WriteString(string(r[i]))
		}
		str = substring.String()

		break
	}

	return str
}
